package com.xsq.netty;

import java.nio.charset.StandardCharsets;
import java.util.List;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

public class MessageDecoder extends ByteToMessageDecoder {

    private ByteBuf mContentByteBuf;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg == null) return;
        if (msg instanceof ByteBuf) {
            ByteBuf byteBuf = (ByteBuf) msg;
//            Log.i("msg_test", "读取一帧数据："+new String(byteBuf.array()));
            readBytes(ctx, byteBuf);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        releaseContentBytes();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        releaseContentBytes();
    }

    private void releaseContentBytes() {
        if (mContentByteBuf != null) {
            mContentByteBuf.release();
            mContentByteBuf = null;
        }
    }

    private void readBytes(ChannelHandlerContext ctx, ByteBuf byteBuf) {
        int readableBytes = byteBuf.readableBytes();
        if (readableBytes > 0) {
            long findMsgLength = 0;
            boolean ifFindFlag = findFlag(byteBuf);
            if (ifFindFlag) {
                findMsgLength = byteBuf.getInt(2);
                if (findMsgLength == readableBytes) {
                    byteBuf.skipBytes(6);
                    ByteBuf contentByteBuf = byteBuf.readBytes((int) findMsgLength-6);
                    fireChannelRead(ctx, contentByteBuf);
                    releaseContentBytes();
                    return;
                }
            }
            if (mContentByteBuf == null) {
                if (ifFindFlag) {
                    mContentByteBuf = byteBuf.copy();
                } else {
                    return;
                }
            } else {
                if (findFlag(byteBuf)) {
                    byteBuf.skipBytes(6);
                }
                mContentByteBuf.writeBytes(byteBuf.readBytes(byteBuf.readableBytes()));
            }
            if (mContentByteBuf != null && mContentByteBuf.isReadable()) {
                byte[] bytes = new byte[mContentByteBuf.readableBytes()];
                mContentByteBuf.getBytes(0, bytes);
            }
            while (mContentByteBuf != null && mContentByteBuf.isReadable()) {
                int readableContentBytes = mContentByteBuf.readableBytes();
                boolean isFindFlag = findFlag(mContentByteBuf);
                if (isFindFlag) {
                    if (readableContentBytes < 6) {
                        break;
                    }
                    findMsgLength = mContentByteBuf.getInt(mContentByteBuf.readerIndex() + 2);
                    if (readableContentBytes >= findMsgLength) {
                        if (findMsgLength < 0) {
                            break;
                        }
                        mContentByteBuf.skipBytes(6);
                        ByteBuf readBytes = mContentByteBuf.readBytes((int) findMsgLength - 6);
                        fireChannelRead(ctx, readBytes);
                        if (mContentByteBuf.readableBytes() == 0) {
                            releaseContentBytes();
                        }
                    } else {
                        break;
                    }
                } else {
                    break;
                }
            }
        }
    }

    private void fireChannelRead(ChannelHandlerContext ctx, ByteBuf byteBuf) {
        if (byteBuf != null) {
            String contentStr = byteBuf.toString(StandardCharsets.UTF_8);
            ctx.fireChannelRead(contentStr);
        }
    }

    private boolean findFlag(ByteBuf byteBuf) {
        if (byteBuf == null) return false;
        if (byteBuf.readableBytes() < 2) return false;
        return byteBuf.getByte(byteBuf.readerIndex()) == (byte) NettyHelper.MSG_TYPE && byteBuf.getByte(byteBuf.readerIndex()+1) == (byte) NettyHelper.MSG_FLAG;
    }

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {

    }

}